10  피처 엔지니어링

Keywords

python, 전처리, 통계, 가설검정, 기계학습, 회귀, 분류, 군집, 모델 학습, 모델 평가

피처 엔지니어링(Feature Engineering)은 기존 데이터를 변형하거나 조합하여 모델이 더 잘 학습할 수 있는 새로운 입력 변수를 만드는 과정이다. 머신러닝에서 “좋은 피처”는 복잡한 알고리즘보다 더 큰 영향을 미치며, 실무 데이터 과학자의 역량이 가장 잘 드러나는 단계이다. 피처 엔지니어링은 도메인 지식과 데이터 탐색을 결합하여 모델이 패턴을 더 쉽게 학습할 수 있도록 돕는다. 이 장에서는 비율 피처, 조합 피처, 변환 피처, 집계 피처 등 다양한 피처 생성 기법과 모델별 전략을 학습한다.

“모델 성능의 상당 부분은 알고리즘이 아니라 피처에서 결정된다.”

예제: 데이터 로드

import seaborn as sns
import pandas as pd
import numpy as np

# 데이터 로드 및 결측치 제거
df = sns.load_dataset("penguins").dropna()

print("데이터 크기:", df.shape)
print("\n사용 가능한 컬럼:")
print(df.columns.tolist())
데이터 크기: (333, 7)

사용 가능한 컬럼:
['species', 'island', 'bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g', 'sex']

10.1 피처 엔지니어링의 중요성

피처 엔지니어링이 중요한 이유는 다음과 같다.

피처 엔지니어링의 영향력

관점 설명 예시
성능 차이의 핵심 같은 모델도 피처에 따라 성능 천차만별 기본 피처 80% → 파생 피처 95%
단순함의 강력함 좋은 피처 + 단순 모델 > 나쁜 피처 + 복잡 모델 선형 회귀 + 좋은 피처 > 복잡한 신경망
도메인 지식 반영 전문가 지식이 모델에 직접 반영되는 단계 의료: 체질량지수(BMI), 금융: 부채비율
해석력 향상 의미 있는 피처는 모델 설명에 도움 “연령대”가 “나이 제곱”보다 이해 쉬움
차원 축소 효과 여러 변수의 관계를 하나로 압축 길이/너비 대신 종횡비 사용

실무 관점

  • 캐글 경진대회에서 상위권 진입의 핵심 요소
  • 프로덕션 환경에서 모델 유지보수성 향상
  • 컴퓨팅 리소스 절약 (단순 모델 사용 가능)
  • 비즈니스 이해관계자와의 커뮤니케이션 개선

10.2 파생 변수 생성 기법

파생 변수는 기존 변수를 수학적으로 변환하거나 조합하여 새로운 정보를 추출하는 방법이다.

10.2.1 비율(Ratio) 피처

두 변수의 비율은 각 변수의 절대값보다 더 의미 있는 정보를 담을 수 있다. 특히 크기가 다른 개체를 비교할 때 유용하다.

예제: 부리 비율 피처 생성

# 부리 길이 대 깊이 비율
df["bill_ratio"] = df["bill_length_mm"] / df["bill_depth_mm"]

print("부리 비율 피처:")
print(df["bill_ratio"].describe())

# 종별 비율 비교
print("\n종별 평균 부리 비율:")
print(df.groupby("species")["bill_ratio"].mean().sort_values())
부리 비율 피처:
count    333.000000
mean       2.607228
std        0.495436
min        1.639810
25%        2.162651
50%        2.576531
75%        3.096970
max        3.612676
Name: bill_ratio, dtype: float64

종별 평균 부리 비율:
species
Adelie       2.121478
Chinstrap    2.653756
Gentoo       3.176602
Name: bill_ratio, dtype: float64

비율 피처는 다음과 같은 상황에서 효과적이다.

  • 신체 비례나 형태를 나타낼 때 (예: 부리 형태, 체형)
  • 스케일이 다른 개체를 비교할 때
  • 효율성이나 밀도를 나타낼 때 (예: 연비, 인구밀도)

추가 예시

# 체중 대 날개 길이 비율 (체중 효율성)
df["body_flipper_ratio"] = df["body_mass_g"] / df["flipper_length_mm"]

# 전체 부리 크기 대비 길이 비율
df["bill_total"] = df["bill_length_mm"] + df["bill_depth_mm"]
df["bill_length_proportion"] = df["bill_length_mm"] / df["bill_total"]

print("\n생성된 비율 피처:")
print(df[["bill_ratio", "body_flipper_ratio", "bill_length_proportion"]].head())

생성된 비율 피처:
   bill_ratio  body_flipper_ratio  bill_length_proportion
0    2.090909           20.718232                0.676471
1    2.270115           20.430108                0.694200
2    2.238889           16.666667                0.691252
4    1.901554           17.875648                0.655357
5    1.907767           19.210526                0.656093

10.2.2 조합 피처 (곱셈, 덧셈)

여러 변수를 곱하거나 더하면 변수 간 상호작용이나 전체 크기를 나타낼 수 있다.

예제: 상호작용 피처 생성

# 체중과 날개 길이의 상호작용 (전체적인 신체 크기)
df["body_flipper_interaction"] = df["body_mass_g"] * df["flipper_length_mm"]

print("상호작용 피처:")
print(df["body_flipper_interaction"].describe())

# 종별 상호작용 피처 비교
print("\n종별 평균 상호작용:")
print(df.groupby("species")["body_flipper_interaction"].mean())
상호작용 피처:
count    3.330000e+02
mean     8.553021e+05
std      2.206116e+05
min      5.158500e+05
25%      6.796500e+05
50%      8.075000e+05
75%      1.021250e+06
max      1.392300e+06
Name: body_flipper_interaction, dtype: float64

종별 평균 상호작용:
species
Adelie       7.059329e+05
Chinstrap    7.327592e+05
Gentoo       1.108586e+06
Name: body_flipper_interaction, dtype: float64

조합 피처 유형

연산 의미 예시
곱셈 (A × B) 상호작용, 면적, 부피 가로 × 세로 = 면적
덧셈 (A + B) 전체 크기, 합계 총 점수, 총 길이
차이 (A - B) 변화량, 격차 가격 변동, 수입-지출
평균 ((A + B) / 2) 중심 경향 평균 성적, 평균 온도

추가 예시

# 전체 부리 크기 (길이 + 깊이)
df["bill_total_size"] = df["bill_length_mm"] + df["bill_depth_mm"]

# 날개와 부리 길이 차이
df["flipper_bill_diff"] = df["flipper_length_mm"] - df["bill_length_mm"]

print("\n조합 피처 샘플:")
print(df[["bill_total_size", "flipper_bill_diff"]].head())

조합 피처 샘플:
   bill_total_size  flipper_bill_diff
0             57.8              141.9
1             56.9              146.5
2             58.3              154.7
4             56.0              156.3
5             59.9              150.7

10.2.3 다항식 피처

변수의 제곱이나 고차항은 비선형 관계를 선형 모델에서 포착할 수 있게 한다.

예제: 제곱 피처 생성

# 체중의 제곱 (비선형 관계 표현)
df["body_mass_squared"] = df["body_mass_g"] ** 2

# 부리 길이의 제곱근 (분포 정규화 효과)
df["bill_length_sqrt"] = np.sqrt(df["bill_length_mm"])

print("다항식 피처 샘플:")
print(df[["body_mass_g", "body_mass_squared", "bill_length_sqrt"]].head())
다항식 피처 샘플:
   body_mass_g  body_mass_squared  bill_length_sqrt
0       3750.0         14062500.0          6.252999
1       3800.0         14440000.0          6.284903
2       3250.0         10562500.0          6.348228
4       3450.0         11902500.0          6.058052
5       3650.0         13322500.0          6.268971

10.3 변환 기반 피처

변환은 분포를 정규화하거나 스케일을 안정화하여 모델 학습을 돕는다.

10.3.1 로그 변환 피처

로그 변환은 왜곡된 분포를 정규화하고 큰 값의 영향을 줄인다.

예제: 로그 변환 피처

# 체중의 로그 변환
df["log_body_mass"] = np.log(df["body_mass_g"])

print("로그 변환 전후 비교:")
print("원본 왜도:", df["body_mass_g"].skew().round(3))
print("로그 왜도:", df["log_body_mass"].skew().round(3))

# 분포 비교
print("\n원본 통계:")
print(df["body_mass_g"].describe())
print("\n로그 변환 통계:")
print(df["log_body_mass"].describe())
로그 변환 전후 비교:
원본 왜도: 0.472
로그 왜도: 0.175

원본 통계:
count     333.000000
mean     4207.057057
std       805.215802
min      2700.000000
25%      3550.000000
50%      4050.000000
75%      4775.000000
max      6300.000000
Name: body_mass_g, dtype: float64

로그 변환 통계:
count    333.000000
mean       8.326667
std        0.188465
min        7.901007
25%        8.174703
50%        8.306472
75%        8.471149
max        8.748305
Name: log_body_mass, dtype: float64

변환의 효과

  • 스케일 안정화: 큰 값과 작은 값의 차이 완화
  • 거리 기반 모델 성능 향상: KNN, SVM 등에서 중요
  • 선형 관계 강화: 지수적 관계를 선형으로 변환
  • 이상치 영향 감소: 극단값을 상대적으로 축소

10.3.2 표준화/정규화 피처

변수를 일정 범위로 변환하여 스케일을 통일한다.

예제: 표준화 피처 생성

from sklearn.preprocessing import StandardScaler

# 주요 수치형 변수들을 표준화
num_cols = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]

scaler = StandardScaler()
df_scaled = pd.DataFrame(
    scaler.fit_transform(df[num_cols]),
    columns=[f"{col}_scaled" for col in num_cols],
    index=df.index
)

# 원본 데이터프레임에 추가
df = pd.concat([df, df_scaled], axis=1)

print("표준화 피처 샘플:")
print(df[[num_cols[0], f"{num_cols[0]}_scaled"]].head())
표준화 피처 샘플:
   bill_length_mm  bill_length_mm_scaled
0            39.1              -0.896042
1            39.5              -0.822788
2            40.3              -0.676280
4            36.7              -1.335566
5            39.3              -0.859415

10.4 구간 기반 피처 (Binning)

연속형 변수를 구간으로 나누어 범주화하면 비선형 관계를 포착하고 해석력을 높일 수 있다.

예제: 체중 구간 피처

# 체중을 3개 구간으로 분류
df["body_mass_group"] = pd.cut(
    df["body_mass_g"],
    bins=[0, 3500, 4500, 7000],
    labels=["small", "medium", "large"]
)

print("체중 구간 분포:")
print(df["body_mass_group"].value_counts())

# 구간별 평균 날개 길이
print("\n구간별 평균 날개 길이:")
print(df.groupby("body_mass_group")["flipper_length_mm"].mean())
체중 구간 분포:
body_mass_group
medium    146
large     112
small      75
Name: count, dtype: int64

구간별 평균 날개 길이:
body_mass_group
small     188.506667
medium    195.383562
large     216.589286
Name: flipper_length_mm, dtype: float64

구간화의 효과

  • 연속값을 해석 가능한 범주로 변환
  • 비선형 관계를 단계적으로 표현
  • 트리 모델에서 분할 힌트 제공
  • 이상치의 영향 완화

추가 예시: 등빈도 구간화

# 사분위수 기준 구간화
df["body_mass_quantile"] = pd.qcut(
    df["body_mass_g"],
    q=4,
    labels=["Q1", "Q2", "Q3", "Q4"]
)

print("사분위수 구간 분포:")
print(df["body_mass_quantile"].value_counts())
사분위수 구간 분포:
body_mass_quantile
Q1    86
Q2    86
Q4    83
Q3    78
Name: count, dtype: int64

10.5 집계 기반 피처 (Aggregation Features)

그룹별 통계량을 계산하여 개체가 그룹 내에서 어떤 위치에 있는지 나타낸다.

10.5.1 그룹 평균 대비 차이

예제: 종별 평균 대비 편차

# 종별 평균 체중 계산
species_mean = df.groupby("species")["body_mass_g"].transform("mean")

# 개체별 편차 계산
df["body_mass_diff_species"] = df["body_mass_g"] - species_mean

print("종별 평균 대비 편차:")
print(df[["species", "body_mass_g", "body_mass_diff_species"]].head(10))

# 편차의 분포
print("\n종별 편차 통계:")
print(df.groupby("species")["body_mass_diff_species"].describe())
종별 평균 대비 편차:
   species  body_mass_g  body_mass_diff_species
0   Adelie       3750.0               43.835616
1   Adelie       3800.0               93.835616
2   Adelie       3250.0             -456.164384
4   Adelie       3450.0             -256.164384
5   Adelie       3650.0              -56.164384
6   Adelie       3625.0              -81.164384
7   Adelie       4675.0              968.835616
12  Adelie       3200.0             -506.164384
13  Adelie       3800.0               93.835616
14  Adelie       4400.0              693.835616

종별 편차 통계:
           count          mean         std          min         25%  \
species                                                               
Adelie     146.0  1.183589e-13  458.620135  -856.164384 -343.664384   
Chinstrap   68.0  8.024953e-14  384.335081 -1033.088235 -245.588235   
Gentoo     119.0 -3.821406e-13  501.476154 -1142.436975 -392.436975   

                 50%         75%          max  
species                                        
Adelie     -6.164384  293.835616  1068.835616  
Chinstrap -33.088235  216.911765  1066.911765  
Gentoo    -42.436975  407.563025  1207.563025  

10.5.2 그룹별 다양한 통계량

예제: 종별 순위와 백분위수

# 종 내 체중 순위
df["body_mass_rank_species"] = df.groupby("species")["body_mass_g"].rank(ascending=False)

# 종 내 체중 백분위수
df["body_mass_pct_species"] = df.groupby("species")["body_mass_g"].rank(pct=True)

print("종 내 순위와 백분위수:")
print(df[["species", "body_mass_g", "body_mass_rank_species", "body_mass_pct_species"]].head(10))
종 내 순위와 백분위수:
   species  body_mass_g  body_mass_rank_species  body_mass_pct_species
0   Adelie       3750.0                    65.5               0.558219
1   Adelie       3800.0                    58.5               0.606164
2   Adelie       3250.0                   121.5               0.174658
4   Adelie       3450.0                   100.5               0.318493
5   Adelie       3650.0                    76.5               0.482877
6   Adelie       3625.0                    78.0               0.472603
7   Adelie       4675.0                     4.0               0.979452
12  Adelie       3200.0                   124.5               0.154110
13  Adelie       3800.0                    58.5               0.606164
14  Adelie       4400.0                    13.0               0.917808

집계 피처의 유형

통계량 의미 활용 예시
mean 그룹 평균 평균 대비 큰지 작은지
std 그룹 분산 그룹 내 변동성
min, max 그룹 범위 극단값과의 거리
rank 그룹 내 순위 상대적 위치
count 그룹 크기 희귀도 판단

10.6 통계 요약 피처

여러 변수의 통계량을 계산하여 개체의 전반적인 특성을 요약한다.

예제: 행 단위 통계 피처

# 주요 수치형 변수 선택
num_cols = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]

# 행 단위 평균 (개체의 전반적인 크기)
df["num_mean"] = df[num_cols].mean(axis=1)

# 행 단위 표준편차 (측정값의 변동성)
df["num_std"] = df[num_cols].std(axis=1)

# 행 단위 최댓값
df["num_max"] = df[num_cols].max(axis=1)

# 행 단위 최솟값
df["num_min"] = df[num_cols].min(axis=1)

# 행 단위 범위 (최댓값 - 최솟값)
df["num_range"] = df["num_max"] - df["num_min"]

print("통계 요약 피처:")
print(df[["num_mean", "num_std", "num_range"]].describe())
통계 요약 피처:
          num_mean      num_std    num_range
count   333.000000   333.000000   333.000000
mean   1117.295420  2061.465442  4189.892192
std     204.948885   400.090276   806.147181
min     738.875000  1309.655694  2683.400000
25%     951.400000  1736.198835  3532.500000
50%    1075.325000  1981.053650  4030.100000
75%    1258.550000  2345.624922  4756.000000
max    1646.350000  3103.740721  6284.800000

통계 요약의 효과

  • 개체의 전체적인 특성을 하나의 값으로 압축
  • 변수 간 일관성 또는 변동성 파악
  • 차원 축소 효과
  • 노이즈 감소 (평균화 효과)

10.7 범주형 조합 피처

여러 범주형 변수를 결합하여 세분화된 그룹을 만든다.

예제: 종과 성별 조합

# 종과 성별을 결합한 새로운 범주
df["species_sex"] = df["species"].astype(str) + "_" + df["sex"].astype(str)

print("종-성별 조합 분포:")
print(df["species_sex"].value_counts())

# 조합별 평균 체중
print("\n종-성별 조합별 평균 체중:")
print(df.groupby("species_sex")["body_mass_g"].mean().sort_values())
종-성별 조합 분포:
species_sex
Adelie_Male         73
Adelie_Female       73
Gentoo_Male         61
Gentoo_Female       58
Chinstrap_Female    34
Chinstrap_Male      34
Name: count, dtype: int64

종-성별 조합별 평균 체중:
species_sex
Adelie_Female       3368.835616
Chinstrap_Female    3527.205882
Chinstrap_Male      3938.970588
Adelie_Male         4043.493151
Gentoo_Female       4679.741379
Gentoo_Male         5484.836066
Name: body_mass_g, dtype: float64

조합 피처 사용 시 주의사항

  • 빈도가 너무 낮은 조합은 과적합 위험 (최소 30개 이상 권장)
  • 조합 수가 너무 많으면 차원이 폭발적으로 증가
  • 도메인 지식상 의미 있는 조합만 생성
  • One-Hot Encoding 시 컬럼 수 급증 주의

추가 예시: 삼원 조합

# 종, 성별, 체중 구간의 삼원 조합
df["species_sex_mass"] = (
    df["species"].astype(str) + "_" + 
    df["sex"].astype(str) + "_" + 
    df["body_mass_group"].astype(str)
)

print("\n삼원 조합 샘플:")
print(df["species_sex_mass"].value_counts().head(10))

삼원 조합 샘플:
species_sex_mass
Adelie_Male_medium         61
Gentoo_Male_large          61
Adelie_Female_small        51
Gentoo_Female_large        42
Chinstrap_Male_medium      28
Adelie_Female_medium       22
Chinstrap_Female_medium    19
Gentoo_Female_medium       16
Chinstrap_Female_small     15
Adelie_Male_large           7
Name: count, dtype: int64

10.8 시간 및 순서형 데이터 피처

시계열 데이터나 순서가 있는 데이터에서는 추가적인 피처 생성 기법을 사용한다.

시간 데이터 피처 예시

# 예시: 날짜 데이터가 있다고 가정
# df["date"] = pd.to_datetime(df["date"])
# 
# # 날짜에서 추출
# df["year"] = df["date"].dt.year
# df["month"] = df["date"].dt.month
# df["day_of_week"] = df["date"].dt.dayofweek
# df["quarter"] = df["date"].dt.quarter
# df["is_weekend"] = df["day_of_week"].isin([5, 6]).astype(int)
# 
# # 주기성 표현 (원형 인코딩)
# df["month_sin"] = np.sin(2 * np.pi * df["month"] / 12)
# df["month_cos"] = np.cos(2 * np.pi * df["month"] / 12)
# 
# # 시간 경과
# df["days_since_start"] = (df["date"] - df["date"].min()).dt.days
# 
# # 이동 평균 (윈도우 = 7일)
# df["rolling_mean_7d"] = df["value"].rolling(window=7).mean()

시간 피처 유형

피처 유형 예시 설명
추출 연, 월, 요일, 시간 날짜/시간에서 구성 요소 분리
주기 sin/cos 변환 원형 데이터의 연속성 표현
경과 시작일로부터 일수 시간의 흐름을 수치로 표현
집계 이동평균, 누적합 과거 패턴 요약
차분 전일 대비 변화량 변화율이나 추세

10.9 피처 선택과의 연결

모든 피처를 사용하는 것이 정답은 아니다. 중복되거나 불필요한 피처는 모델 성능을 저하시킬 수 있다.

예제: 상관관계 분석

import matplotlib.pyplot as plt
import seaborn as sns

# 주요 피처들의 상관관계
feature_cols = [
    "bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g",
    "bill_ratio", "body_flipper_interaction", "log_body_mass"
]

corr_matrix = df[feature_cols].corr()

# 히트맵 시각화
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", center=0, fmt=".2f")
plt.title("Feature Correlation Matrix")
plt.tight_layout()
plt.show()

피처 선택 기준

  • 높은 상관관계 (|r| > 0.9): 중복 정보, 하나만 선택
  • 타겟과의 상관관계: 타겟과 관련 없는 피처 제거
  • 다중공선성: VIF(Variance Inflation Factor) > 10이면 문제
  • 피처 중요도: 트리 모델의 feature_importances_ 활용

예제: 중요도 기반 선택

from sklearn.ensemble import RandomForestClassifier

# 간단한 모델로 피처 중요도 확인
X = df[feature_cols].dropna()
y = df.loc[X.index, "species"]

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)

# 피처 중요도 출력
importance_df = pd.DataFrame({
    "feature": feature_cols,
    "importance": rf.feature_importances_
}).sort_values("importance", ascending=False)

print("피처 중요도:")
print(importance_df)
피처 중요도:
                    feature  importance
4                bill_ratio    0.326713
0            bill_length_mm    0.184320
2         flipper_length_mm    0.160196
5  body_flipper_interaction    0.151781
1             bill_depth_mm    0.112097
6             log_body_mass    0.037838
3               body_mass_g    0.027055

10.10 모델별 피처 엔지니어링 전략

모델의 특성에 따라 효과적인 피처가 다르다.

모델별 피처 전략

모델 유형 중요 피처 이유 권장 기법
선형 모델 (회귀, 로지스틱) 스케일링, 상호작용 변수 간 관계를 명시적으로 표현 필요 표준화, 다항식, 상호작용
KNN, SVM 스케일링, 분포 정규화 거리 기반이라 스케일에 민감 Min-Max, 로그 변환
트리 계열 (RF, XGBoost) 비선형 파생, 범주화 분할 힌트 제공, 비선형 자동 처리 비율, Binning, 집계
신경망 단순 + 대량 데이터 자체적으로 복잡한 피처 학습 정규화, 임베딩
Naive Bayes 독립 피처 피처 간 독립성 가정 단순 변환, 중복 제거

모델별 예시

# 선형 모델용: 상호작용 피처
from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(df[["bill_length_mm", "bill_depth_mm"]])
print("다항식 피처 개수:", X_poly.shape[1])

# 트리 모델용: 범주화 + 집계
tree_features = ["body_mass_group", "body_mass_diff_species", "bill_ratio"]
print("\n트리 모델 추천 피처:", tree_features)
다항식 피처 개수: 5

트리 모델 추천 피처: ['body_mass_group', 'body_mass_diff_species', 'bill_ratio']

10.11 전처리 전체 흐름에서의 위치

피처 엔지니어링은 전처리의 후반부에 위치하며, 정제된 데이터를 바탕으로 수행한다.

데이터 전처리 전체 흐름

1. 데이터 로드
   ↓
2. 결측치 처리 (제거/대체)
   ↓
3. 이상치 탐지 및 처리
   ↓
4. 스케일링 (변수 크기 통일)
   ↓
5. 분포 변환 (왜도 정규화)
   ↓
6. 인코딩 (범주형 → 수치형)
   ↓
7. 불균형 데이터 처리
   ↓
8. 피처 엔지니어링 ← 현재 장
   ↓
9. 피처 선택 (중요 피처 추출)
   ↓
10. 모델링

단계별 피처 생성 시점

  • 결측치 처리 전: X (결측치가 계산을 방해)
  • 이상치 처리 전: △ (이상치가 비율/평균에 영향)
  • 스케일링 전: O (원본 값으로 비율 계산 후 스케일링)
  • 인코딩 후: O (범주형 조합 피처 생성 가능)
  • 피처 선택 전: O (모든 후보 피처 생성 후 선택)

10.12 요약

이 장에서는 피처 엔지니어링의 개념과 다양한 기법을 학습했다. 주요 내용은 다음과 같다.

피처 엔지니어링 기법 정리

기법 방법 효과 예시
비율 A / B 상대적 크기, 형태 부리 길이/깊이 비율
조합 A × B, A + B 상호작용, 전체 크기 체중 × 날개 길이
변환 log, sqrt, 제곱 분포 정규화, 비선형 관계 log(체중)
구간화 cut, qcut 비선형 포착, 해석력 체중 그룹(소/중/대)
집계 groupby + transform 그룹 내 상대적 위치 종별 평균 대비 편차
통계 요약 mean, std, max 전체 특성 압축 측정값 평균
범주 조합 문자열 결합 세분화된 그룹 종_성별 조합
시계열 lag, rolling, diff 시간 패턴, 추세 7일 이동평균

피처 엔지니어링 모범 사례

  1. EDA 먼저: 데이터 탐색을 통해 패턴 발견 후 피처 생성
  2. 도메인 지식 활용: 전문가 의견이나 논문의 아이디어 반영
  3. 단순하게 시작: 복잡한 피처보다 직관적인 피처부터
  4. 반복적 개선: 모델 성능을 확인하며 점진적으로 추가
  5. 과적합 주의: 학습 데이터로만 통계량 계산, 테스트 누수 방지
  6. 문서화: 피처 생성 논리와 의미를 명확히 기록
  7. 재현성 확보: 파이프라인으로 자동화하여 일관성 유지

피처 엔지니어링 체크리스트

피처 엔지니어링은 데이터 과학의 핵심 기술이자 예술이다. 도메인 지식, 창의성, 그리고 반복적인 실험을 통해 모델 성능을 크게 향상시킬 수 있다. 좋은 피처는 복잡한 모델보다 강력하며, 실무에서 데이터 과학자의 역량을 가장 잘 드러내는 단계이다. 다음 단계로는 생성된 피처를 바탕으로 모델을 학습하고 평가하는 과정을 진행할 수 있다.